Skip to content

[SPARK-56054][SQL] Undo handling aliased assignments in MERGE INTO schema evolution and add tests #55239

Open
johanl-db wants to merge 4 commits intoapache:masterfrom
johanl-db:SPARK-56054-merge-into-schema-evolution-alias
Open

[SPARK-56054][SQL] Undo handling aliased assignments in MERGE INTO schema evolution and add tests #55239
johanl-db wants to merge 4 commits intoapache:masterfrom
johanl-db:SPARK-56054-merge-into-schema-evolution-alias

Conversation

@johanl-db
Copy link
Copy Markdown
Contributor

@johanl-db johanl-db commented Apr 7, 2026

What changes were proposed in this pull request?

Follow up from #54891 in particular this comment.

Adds more tests covering schema evolution in MERGE INTO when the assignment contains an alias.
This change also undoes the fix from #54891. On closer inspection, this isn't needed in Spark as Spark already removes trivial aliases on nested field accessors in MERGE in resolveExprInAssignment, which is what the change aimed to allow. See this test added here covering trivial aliases implictily added on nested field access.

Delta doesn't strip aliases during resolution in that way and will require special handling, but that's up to Delta to implement in its custom resolution logic to replicate what Spark already does

How was this patch tested?

Adds tests covering MERGE INTO schema evolution with aliases in assignments

Copy link
Copy Markdown
Member

@szehon-ho szehon-ho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are all DataFrame API, wondering is there any equivalent in SQL? Be good to abstract it out if possible

If not, maybe we can we make a new file MergeIntoSchemaEvolutionExtraDataFrameTests to make them only run in DataFrame mode?

It is a bit of a mess now due to the inheritance patterns

@johanl-db
Copy link
Copy Markdown
Contributor Author

I moved the tests to a dedicated trait for dataframe tests.

There's no SQL equivalent, it's not possible to specify an alias in an assignment expression using SQL afaict: SET col = source.col AS other_col

@johanl-db johanl-db requested a review from szehon-ho April 9, 2026 15:00
spark.table("source")
.mergeInto(tableNameAsString,
col(s"$tableNameAsString.pk") === col("source.pk"))
.whenMatched().update(Map("info" -> col("source.info").as("info")))
Copy link
Copy Markdown
Contributor

@aokolnychyi aokolnychyi Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, this seems like a behavior change compared to the initial PR then? The code in master would evolve the schema in this case because we had that alias support?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. The main motivation for the initial PR adding support for alias was to support nested assignments SET col.x = s.col.x, which translates to Assignment("col.x", Alias(GetStructField("col", "x"), "x")
I've noticed in the meantime that Spark actually strips the alias on struct field access after resolution (Delta doesn't).

We don't have a strong argument to support the remaining cases where the user provides an explicit alias using the dataframe API, so I'd rather not allow these

.mergeInto(tableNameAsString,
col(s"$tableNameAsString.pk") === col("source.pk"))
.whenMatched().update(Map(
"info" -> col("source.info").as("something_else")))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does Delta behave in this case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta allows schema evolution here, but only because it allows arbitrary expressions on the right hand side of the assignment. col("source.info").as("something_else") can qualifies for schema evolution the same way col("source.other_column").plus(lit(1)) does.
Spark rejects both (with this change)

@aokolnychyi
Copy link
Copy Markdown
Contributor

@johanl-db, what about cases when the source query has an alias?

MERGE INTO t
USING (SELECT 'blah' AS col1, 1 AS col2 FROM source) AS s
ON false
WHEN NOT MATCHED THEN INSERT *

@johanl-db johanl-db changed the title [SPARK-56054][SQL] Add test for MERGE INTO schema evolution with aliased assignments [SPARK-56054][SQL] Undo handling aliased assignments in MERGE INTO schema evolution and add tests Apr 14, 2026
@johanl-db
Copy link
Copy Markdown
Contributor Author

@johanl-db, what about cases when the source query has an alias?

MERGE INTO t
USING (SELECT 'blah' AS col1, 1 AS col2 FROM source) AS s
ON false
WHEN NOT MATCHED THEN INSERT *

Discussed directly with @aokolnychyi and @szehon-ho :
The shape of source doesn't matter at all, the only parts that matter when performing schema evolution are:

  • The schema of the source
  • The assignment expressions in the match clauses

MERGE doesn't look inside the source query to see what it contains, so the aliases there are irrelevant.
This case will trigger schema evolution for all new columns in the source schema, since there's an INSERT * assignment.

@johanl-db johanl-db requested a review from aokolnychyi April 14, 2026 06:33
@johanl-db
Copy link
Copy Markdown
Contributor Author

CI is failing due to formatting on files that are not touched in this PR. Likely from #55281

Copy link
Copy Markdown
Member

@szehon-ho szehon-ho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this one is ready to go @cloud-fan

i also added the test requested by @aokolnychyi in #55304 (i didnt see the comment), we can add it separately , or optionally as part this pr, i guess it doesnt matter. As we looked into it together, its a bit orthogonal to this pr (the aliases within source doens't matter, to MERGE it just comes as a source table)

@szehon-ho
Copy link
Copy Markdown
Member

also , apparently this ci error is fixed by #55334

@johanl-db
Copy link
Copy Markdown
Contributor Author

I think this one is ready to go @cloud-fan

i also added the test requested by @aokolnychyi in #55304 (i didnt see the comment), we can add it separately , or optionally as part this pr, i guess it doesnt matter. As we looked into it together, its a bit orthogonal to this pr (the aliases within source doens't matter, to MERGE it just comes as a source table)

@szehon-ho I picked up your test from #55304 in this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants